package xin.infinite.filter;


import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import xin.infinite.service.UserServiceDubbo;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


@Component
@RefreshScope
public class MyFilter implements GlobalFilter, Ordered {


    private static ConcurrentHashMap<String, List<IpEntity>> map=new ConcurrentHashMap<>();

    /**
     * 单位时间秒数
     */
    @Value("${ip-strategy.second}")
    private  int second;

    /**
     * 单位时间内最大请求次数
     */
    @Value("${ip-strategy.maxRequest}")
    private  int maxRequest;



    @Reference(check = false)
    private UserServiceDubbo userService;


    public MyFilter(){
        super();
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                clear();
            }
        },1,1, TimeUnit.SECONDS);
    }


    /**
     * 添加全局过滤器，进⾏IP注册接⼝的防暴刷控制，超过阈值直接返回错误码及错误信息（错
     * 误码：303，错误信息：您频繁进⾏注册，请求已被拒绝）
     * 添加全局过滤，进⾏token的验证，⽤户微服务和验证码微服务的请求不过滤（⽹关调⽤下游
     * ⽤户微服务的token验证接⼝）
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        //注册接口IP防爆刷
        if(path.startsWith("/api/user/register")){

            String ip = request.getRemoteAddress().getHostString();
            System.out.println("当前请求IP:"+ip+"当前IP单位时间类请求次数："+((map.get(ip)==null)?0:map.get(ip).size()));
            Long time=System.currentTimeMillis();
            IpEntity ipEntity=new IpEntity(ip,time);
            if(map.get(ip)!=null){
                map.get(ip).add(ipEntity);
                //判断ip爆刷
                if(checkCount(ip)){
                    System.out.println("当前IP访问过于频繁");
                    ServerHttpResponse response = exchange.getResponse();
                    // 拒绝访问，返回303
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    String data = "Request be denied!";
                    DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                    return response.writeWith(Mono.just(wrap));
                }
            }else {
                List<IpEntity> list=new CopyOnWriteArrayList<>();
                list.add(ipEntity);
                map.put(ip,list);
            }
        }
        //全局token验证（不验证用户和验证码服务）
        if(!path.startsWith("/api/user")&&!path.startsWith("/api/code")){
            ServerHttpResponse response = exchange.getResponse();
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie token = cookies.getFirst("token");
            String url = "http://www.test.com/static/login.html";
            if(token==null){
                //303状态码表示由于请求对应的资源存在着另一个URI，应使用GET方法定向获取请求的资源
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION,url);
                return response.setComplete();
            }else {
                String tokenName = token.getName();
                String info = userService.getEmail(tokenName);
                if(StringUtils.isEmpty(info)){
                    //303状态码表示由于请求对应的资源存在着另一个URI，应使用GET方法定向获取请求的资源
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,url);
                    return response.setComplete();
                }
            }
        }
        return chain.filter(exchange);
    }


    /**
     * 判断是否超出限制
     * @param ip
     * @return
     */
    private boolean checkCount(String ip){
        List<IpEntity> list = map.get(ip);
        if(list!=null){
            return list.size() > maxRequest;
        }
        return false;
    }

    /**
     * 清理过期的数据
     */
    private  void clear(){
        for (String key : map.keySet()) {
            List<IpEntity> list = map.get(key);
            for (IpEntity ipEntity : list) {
                if((System.currentTimeMillis()-ipEntity.getRequestTime())/1000>second){
                    list.remove(ipEntity);
                }
            }
        }
    }


    /**
     * 返回值表示当前过滤器的顺序(优先级)，数值越⼩，优先级越⾼
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
